new Vue({
    el: '#app',
    data() {
        return {
            // 当前激活的折叠面板
            activeCollapse: [''],
            // 上传的文件对象
            file: null,           // 打卡文件
            summaryfile: null,    // 汇总文件
            // 处理后的数据
            processedData: null,       // 打卡处理结果
            summaryTableData: null,    // 汇总处理结果
            // 系统配置对象
            config: {
                checkInTableConfig: {
                    empIdCol: 3,        // 工号列索引
                    nameCol: 0,         // 姓名列索引
                    startCol: 6,        // 考勤开始列索引
                    headCol: 3,         // 表头开始行号
                    departmentCol: 2,   // 部门列索引
                    workStart: "08:00", // 上班时间
                    workEnd: "17:00",   // 下班时间
                    restStart: "11:30", // 午休开始时间
                    restEnd: "12:30",   // 午休结束时间
                    dinnerStart: "17:00", // 晚休开始时间
                    dinnerEnd: "17:30",   // 晚休结束时间
                    lateTime: 10,         // 允许迟到时间（分钟）
                    //都德辉,罗石柱,刘玉春,马连锁,施磊,唐彬彬,邱红梅,张月,赵红,褚立洋,韩宇,何琴,张力,王地广,王晏青
                    Staff: "SH00007,SH00002,SH00062,SH00173,SH00367,SH00102,SH00372,SH00027,SH00008,SH00035,SH00006,SH00029,SH00012,SH00034,RM00007", // 管理员工号列表
                    departmentList: "财务,人事,采购,外协!综合@软件,电气,机械,项目!技术@生产!生产" // 部门层级关系
                },
                SummaryTableConfig: {
                    empIdCol: 3,    // 工号列索引
                    nameCol: 0,     // 姓名列索引
                    startCol: 34,   // 考勤开始列索引
                    headCol: 4,     // 表头开始行号
                }
            },
            // 部门层级关系映射
            organizationalList: {},
            // 考勤日期长度
            dateLength: 0,
            // 打卡数据对象
            checkInTableObjectData: {},
            // 原始JSON数据
            jsonData: null,
            // 每日工作时长
            workinghours: 0,
            // 晚休时长
            eveningRestHour: 0,
            // 汇总表JSON数据
            summaryjsonData: null,
            // 迟到时间转换（小时）
            lateTimeConvert: 0
        }
    },
    mounted() {
        // 组件挂载时加载配置
        this.loadConfig();
    },
    methods: {
        // 文件上传处理
        handleFileChange(file) {
            // 处理打卡文件上传，获取原始文件对象
            this.file = file.raw;
        },
        handleSummaryFileChange(summaryfile) {
            // 处理汇总文件上传，获取原始文件对象
            this.summaryfile = summaryfile.raw;
        },

        // 配置管理
        loadConfig() {
            // 从 localStorage 加载配置，如果没有则保存默认配置
            const savedConfig = localStorage.getItem('attendanceConfig');
            if (savedConfig) {
                try {
                    this.config = JSON.parse(savedConfig);
                } catch (e) {
                    this.saveConfig();
                }
            } else {
                this.saveConfig();
            }
        },
        saveConfig() {
            // 保存配置到 localStorage
            try {
                localStorage.setItem('attendanceConfig', JSON.stringify(this.config, null, 2));
                this.$message.success('保存成功!');
            } catch (e) {
                this.$message.error('保存失败!' + e);
            }
        },
        resetConfig() {
            // 重置配置为默认值
            this.config = {
                checkInTableConfig: {
                    empIdCol: 3,
                    nameCol: 0,
                    startCol: 6,
                    headCol: 3,
                    departmentCol: 2,
                    workStart: "08:00",
                    workEnd: "17:00",
                    restStart: "11:30",
                    restEnd: "12:30",
                    dinnerStart: "17:00",
                    dinnerEnd: "17:30",
                    lateTime: 10,
                    Staff: "SH00007,SH00002,SH00062,SH00173,SH00367,SH00102,SH00372,SH00027,SH00008,SH00035,SH00006,SH00029,SH00012,SH00034,RM00007",
                    departmentList: "财务,人事,采购,外协!综合@软件,电气,机械,项目!技术@生产!生产"
                },
                SummaryTableConfig: {
                    empIdCol: 3,
                    nameCol: 0,
                    startCol: 34,
                    headCol: 4,
                }
            };
            this.saveConfig();
        },

        // 文件处理核心逻辑
        async processFile() {
            // 处理打卡文件，确保已选择文件
            if (!this.file) return this.$message.error('请先选择打卡文件');
            const reader = new FileReader();
            reader.onload = e => {
                const data = new Uint8Array(e.target.result);
                const workbook = XLSX.read(data, { type: 'array' });
                const sheet = workbook.Sheets[workbook.SheetNames[0]];
                const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
                this.jsonData = jsonData;
                this.processedData = this.processattendanceData(jsonData);
            };
            reader.readAsArrayBuffer(this.file);
        },

        async summaryfileProcessFile() {
            // 处理汇总文件，确保先上传考勤文件
            if (!this.file) return this.$message.error('请先上传考勤文件');
            if (!this.summaryfile) return this.$message.error('请先选择汇总文件');
            const data = await this.readExcelFile(this.summaryfile);
            this.summaryjsonData = data;
            this.summaryTableData = this.processSummaryData(data);
        },

        async readExcelFile(file) {
            // 读取 Excel 文件并返回 JSON 数据
            return new Promise((resolve) => {
                const reader = new FileReader();
                reader.onload = e => {
                    const data = new Uint8Array(e.target.result);
                    const workbook = XLSX.read(data, { type: 'array' });
                    const sheet = workbook.Sheets[workbook.SheetNames[0]];
                    resolve(XLSX.utils.sheet_to_json(sheet, { header: 1 }));
                };
                reader.readAsArrayBuffer(file);
            });
        },

        // 时间处理工具函数
        timeToMinutes(timeStr) {
            // 将时间字符串转换为分钟数，例如 "08:00" -> 480
            const [h, m] = timeStr.split(':').map(Number);
            return h * 60 + m;
        },

        calcDuration(startMins, endMins) {
            // 计算时间间隔（分钟），确保不会为负
            return Math.max(0, endMins - startMins);
        },

        specialRound(hours) {
            // 特殊四舍五入处理：>=0.5 -> +0.5，>=0.05 -> 接近0.5倍数，否则取整
            const decimal = hours % 1;
            const integer = Math.floor(hours);
            if (decimal >= 0.5) return integer + 0.5;
            else if (decimal >= 0.05) return integer + Math.floor(decimal * 2) / 2;
            return integer;
        },

        parseTimes(cellValue) {
            // 解析单元格中的时间值，支持多行时间（换行符分隔）
            if (!cellValue) return [];
            return cellValue.split(/[\r\n\r]+/)
                .map(t => t.trim())
                .filter(t => t.match(/^\d{2}:\d{2}$/));
        },

        // 部门处理
        extractKey(str) {
            // 从字符串中提取部门关键词
            const regex = new RegExp(`(${Object.keys(this.organizationalList).join('|')})`);
            return str.replace(/[^\u4e00-\u9fa5]/g, '').match(regex)?.[0] || null;
        },

        getDepartment(input) {
            // 获取部门名称，默认返回“综合”
            const key = this.extractKey(input);
            return this.organizationalList[key] || '综合';
        },

        // 工时计算
        calculateWorkDuration(workStart, workEnd, restStart, restEnd) {
            // 计算工作时长（小时），排除午休时间
            const workStartMinutes = this.timeToMinutes(workStart);
            const workEndMinutes = this.timeToMinutes(workEnd);
            const restStartMinutes = this.timeToMinutes(restStart);
            const restEndMinutes = this.timeToMinutes(restEnd);
            const totalWorkMinutes = workEndMinutes - workStartMinutes;
            const restMinutes = restEndMinutes - restStartMinutes;
            return (totalWorkMinutes - restMinutes) / 60;
        },
        eveningRestDuration(dinnerStart, dinnerEnd) {
            // 计算晚休时长（小时）
            const workStartMinutes = this.timeToMinutes(dinnerStart);
            const workEndMinutes = this.timeToMinutes(dinnerEnd);
            const totalWorkMinutes = workEndMinutes - workStartMinutes;
            return totalWorkMinutes / 60;
        },

        // 考勤数据处理
        processattendanceData(jsonData) {
            // 处理考勤数据，初始化并生成结果
            this.initializeAttendanceData(jsonData);
            return this.generateAttendanceResults();
        },

        initializeAttendanceData(jsonData) {
            // 初始化考勤数据，计算日期长度、工作时长等
            this.dateLength = this.jsonData[this.config.checkInTableConfig.headCol - 1].length - this.config.checkInTableConfig.startCol;
            this.workinghours = this.calculateWorkDuration(
                this.config.checkInTableConfig.workStart,
                this.config.checkInTableConfig.workEnd,
                this.config.checkInTableConfig.restStart,
                this.config.checkInTableConfig.restEnd
            );
            this.eveningRestHour = this.eveningRestDuration(
                this.config.checkInTableConfig.dinnerStart,
                this.config.checkInTableConfig.dinnerEnd
            );
            this.initializeDepartmentList();
            this.lateTimeConvert = Math.round(this.config.checkInTableConfig.lateTime / 60 * 100) / 100;
        },

        initializeDepartmentList() {
            // 初始化部门列表，解析部门层级关系
            const regex = /([^!@]+)!([^@]+)/g;
            let match;
            while ((match = regex.exec(this.config.checkInTableConfig.departmentList)) !== null) {
                const [_, subDeptStr, parent] = match;
                subDeptStr.split(',').forEach(subDept => {
                    this.organizationalList[subDept.trim()] = parent.trim();
                });
            }
        },

        generateAttendanceResults() {
            // 生成考勤结果，包含表头和员工数据
            const results = [];
            const header = this.generateHeader();
            results.push(header);

            for (let i = this.config.checkInTableConfig.headCol; i < this.jsonData.length; i++) {
                const row = this.jsonData[i];
                const empId = row[this.config.checkInTableConfig.empIdCol];
                const name = row[this.config.checkInTableConfig.nameCol];
                const department = row[this.config.checkInTableConfig.departmentCol];

                if (!empId || !name) continue;

                const departmentName = this.getDepartment(department);
                const exists = this.config.checkInTableConfig.Staff.split(',').includes(empId);
                const employeeData = this.processEmployeeData(row, empId, name, departmentName, exists);

                if (employeeData) {
                    results.push(...this.generateEmployeeRows(employeeData));
                }
            }
            return results;
        },

        generateHeader() {
            // 生成表头，包含日期和异常信息列
            const header = ['工号', '姓名', '部门'];
            for (let i = this.config.checkInTableConfig.startCol; i < this.config.checkInTableConfig.startCol + this.dateLength; i++) {
                header.push(this.jsonData[this.config.checkInTableConfig.headCol - 1][i]);
            }
            header.push('异常信息');
            return header;
        },

        processEmployeeData(row, empId, name, department, isAdmin) {
            // 处理员工数据，生成考勤对象
            const employeeData = {
                empId,
                name,
                department,
                identity: isAdmin ? "admin" : "staff",
                normalTimeArr: new Array(this.dateLength).fill(''),  // 工作时间，初始化为空字符串
                overTimeArr: new Array(this.dateLength).fill(''),    // 加班时间，初始化为空字符串
                attendanceData: new Array(this.dateLength).fill(''), // 打卡数据
                vacationData: new Array(this.dateLength).fill(''),   // 事假数据
                matterArr: [],       // 假期事件数组
                contrastArr: new Array(this.dateLength).fill(''),    // 异常信息
                allmatterArr: [],
                pMatterArr: [],
            };
            for (let col = this.config.checkInTableConfig.startCol; col < this.config.checkInTableConfig.startCol + this.dateLength; col++) {
                const times = this.parseTimes(row[col]);
                const timeStr = times.length > 0 ? times.join('\r\n') : "";
                const dayIndex = col - this.config.checkInTableConfig.startCol;
                employeeData.attendanceData[dayIndex] = timeStr; // 第一行：打卡数据

                const timeCalculation = isAdmin ? this.administratorsWorkTime(times) : this.calculateNormalTime(times);
                this.processTimeCalculation(employeeData, timeCalculation, col, isAdmin);

                // 计算加班时间，确保为 Number 类型
                const overtime=timeCalculation.overtime;
                employeeData.overTimeArr[dayIndex] = overtime > 0 ? this.specialRound(overtime) : ''; // Number 或空字符串
            }

            this.checkInTableObjectData[empId] = employeeData;
            return employeeData;
        },

        administratorsWorkTime(times) {
            // 计算管理员的工作时间和加班时间
            // 需求1：晚上打卡时间减去早上打卡时间，减去午休时间，超过8小时包含晚饭时间则减去，不包含不减
           
            let normal = 0;  // 正常工作时间（小时）
            let overtime = 0;  // 加班时间（小时）
            let error = null;  // 错误信息
            let oneTime = null;  // 单次打卡时间
            if(times.length == 0){
                return { normal, overtime, error, oneTime }; // 返回默认值
            }
            if (times.length >= 2) {
                // 获取最早和最晚打卡时间
                const [start, end] = [times[0], times[times.length - 1]];
                let startMins = this.timeToMinutes(start);  // 早上打卡时间（分钟）
                let endMins = this.timeToMinutes(end);  // 晚上打卡时间（分钟）

                // 处理跨天情况（例如晚上打卡到第二天）
                if (endMins < startMins) endMins += 24 * 60;

                // 从配置中获取工作时间和休息时间
                const workStart = this.timeToMinutes(this.config.checkInTableConfig.workStart);  // 标准上班时间 08:00
                const workEnd = this.timeToMinutes(this.config.checkInTableConfig.workEnd);  // 标准下班时间 17:00
                const restStart = this.timeToMinutes(this.config.checkInTableConfig.restStart);  // 午休开始时间 11:30
                const restEnd = this.timeToMinutes(this.config.checkInTableConfig.restEnd);  // 午休结束时间 12:30
                const dinnerStart = this.timeToMinutes(this.config.checkInTableConfig.dinnerStart);  // 晚饭开始时间 17:00
                const dinnerEnd = this.timeToMinutes(this.config.checkInTableConfig.dinnerEnd);  // 晚饭结束时间 17:30

                // 计算总打卡时间（分钟）
                let totalDuration = endMins - startMins;

                // 扣除午休时间（如果打卡时间包含午休时间）
                if (restStart && restEnd && totalDuration > 0 && restStart < endMins && restEnd > startMins) {
                    const overlapStart = Math.max(startMins, restStart);  // 午休与打卡时间的重叠开始
                    const overlapEnd = Math.min(endMins, restEnd);  // 午休与打卡时间的重叠结束
                    if (overlapStart < overlapEnd) {
                        totalDuration -= (overlapEnd - overlapStart);  // 减去午休时间
                    }
                }

                // 将总分钟数转换为小时
                let totalHours = totalDuration / 60;

                // 计算加班时间：如果总时间超过8小时
                if (totalHours > this.workinghours) {
                    overtime = totalHours - this.workinghours;  // 超过8小时的部分计入加班时间
                    normal = this.workinghours;  // 正常工作时间固定为8小时

                    // 如果加班时间包含晚饭时间（17:00 - 17:30），则扣除
                    if (endMins > dinnerStart && dinnerEnd > workEnd) {
                        const overlapStart = Math.max(workEnd, dinnerStart);  // 晚饭与加班时间的重叠开始
                        const overlapEnd = Math.min(endMins, dinnerEnd);  // 晚饭与加班时间的重叠结束
                        if (overtime>(overlapEnd - overlapStart) / 60&&overlapStart < overlapEnd) {
                            overtime -= (overlapEnd - overlapStart) / 60;  // 从加班时间中扣除晚饭时间
                        }
                    }
                }else{
                    normal = totalHours;  // 正常工作时间不超过8小时
                }

                // 处理迟到补偿：如果正常工作时间不足8小时，应用迟到时间补偿
                if (normal < this.workinghours) {
                    const compensated = normal + this.lateTime;
                    if (compensated >= this.workinghours) {
                        normal = this.workinghours;  // 补偿后达到8小时
                    }
                }

            } else if (times.length === 1) {
                // 单次打卡情况，记录异常信息
                error = `缺勤，只有一次打卡时间为${times[0]}`;
                oneTime = times[0];
            }
            normal=this.specialRound(normal)
            overtime=this.specialRound(overtime)
            return { normal, overtime, error, oneTime };  // 返回计算结果
        },

        /**
         * 计算普通员工的正常工作时间,加班时间
         * @param {Array} times - 员工的打卡时间数组，每个元素都是一个表示时间的字符串
         * @returns {Object} - 返回一个对象，包含正常工作时间（normal）、错误信息（error）和单次打卡时间（oneTime）
         */
        calculateNormalTime(times) {
            // 初始化总工作时间、错误信息和单次打卡时间变量
            let total = 0;
            let error = null;
            let oneTime = null;
            let overtime=0;
            const workStart = this.timeToMinutes(this.config.checkInTableConfig.workStart);
            const workEnd = this.timeToMinutes(this.config.checkInTableConfig.workEnd);
            const restStart = this.timeToMinutes(this.config.checkInTableConfig.restStart);
            const restEnd = this.timeToMinutes(this.config.checkInTableConfig.restEnd);
            const dinnerStart = this.timeToMinutes(this.config.checkInTableConfig.dinnerStart);  // 晚饭开始时间 17:00
            const dinnerEnd = this.timeToMinutes(this.config.checkInTableConfig.dinnerEnd);  // 晚饭结束时间 17:30
            // 如果打卡时间数组长度大于等于2，表示至少有两次打卡，可以计算工作时间
            if (times.length >= 2) {
                // 获取最早和最晚的打卡时间
                let [start, end] = [times[0], times[times.length - 1]];
                // 将打卡时间转换为分钟数，便于计算
                let startMinutes = this.timeToMinutes(start);
                let endMinutes = this.timeToMinutes(end);
        
                // 如果结束时间小于开始时间，表示跨越了午夜，需要加上24小时的分钟数
                if (endMinutes < startMinutes) endMinutes += 24 * 60;
        
                // 获取工作日的开始和结束时间，以及休息时间的开始和结束时间，都转换为分钟数
                
                // 计算正常工作时间，排除休息时间
                total += this.calcDuration(Math.max(startMinutes, workStart), Math.min(endMinutes, restStart));
                total += this.calcDuration(Math.max(startMinutes, restEnd), Math.min(endMinutes, workEnd));
                total=total/60;
                if(endMinutes>dinnerEnd){
                    overtime=(endMinutes-dinnerEnd)/60;
                }
                 // 处理迟到补偿：如果正常工作时间不足8小时，应用迟到时间补偿
                if (total < this.workinghours) {
                    const compensated = total + this.lateTimeConvert;
                    //时间补偿
                    if (compensated >= this.workinghours) {
                        total = this.workinghours;  // 补偿后达到8小时
                    }
                }else{
                    normal = this.workinghours;  // 正常工作时间固定为8小时
                }
                
            } else if (times.length === 1) {
                // 如果只有一次打卡记录，记录单次打卡时间和错误信息
                oneTime = times[0];
                error = `缺勤，只有一次打卡时间为${times[0]}`;
            }
            
             
            // 对总工作时间进行特殊四舍五入处理
            total=this.specialRound(total);
            overtime=this.specialRound(overtime);
            // 返回计算结果，包括正常工作时间、错误信息和单次打卡时间
            return { normal: total,overtime, error, oneTime };
        },
        /**
         * 计算员工工作时间并更新员工数据
         * 该函数根据提供的计算结果更新员工的正常工作时间和加班时间，同时处理特殊逻辑如错误标记和一次性时间记录
         * 
         * @param {Object} employeeData - 员工数据对象，包含需要更新的正常工作时间和加班时间数组
         * @param {Object} calculation - 计算结果对象，包含正常工作时间（normal）、加班时间（overtime）和可能的错误信息（error）
         * @param {Number} col - 列索引，用于计算在员工数据数组中的正确位置
         * @param {Boolean} isAdmin - 管理员标志，未在当前代码段中使用，可能在上下文中具有意义
         */
        processTimeCalculation(employeeData, calculation, col, isAdmin) {
            // 处理时间计算逻辑，确保数值数据为 Number 类型
            const dayIndex = col - this.config.checkInTableConfig.startCol;
            let normal = calculation.normal;
            let overtime = calculation.overtime || 0;
        
            // 如果计算结果包含错误信息，将其记录在对比数组中
            if (calculation.error) {
                employeeData.contrastArr[dayIndex] = calculation.error;
            }
        
            // 处理一次性时间记录，保持为字符串格式
            if (calculation.oneTime) {
                employeeData.normalTimeArr[dayIndex] = calculation.oneTime;
            } else {
                // 更新正常工作时间数组，仅当正常工作时间大于0时，使用特殊四舍五入方法
                employeeData.normalTimeArr[dayIndex] = normal > 0 ? this.specialRound(normal) : ''; // Number 或空字符串
                // 更新加班时间数组，仅当加班时间大于0时，使用特殊四舍五入方法
                employeeData.overTimeArr[dayIndex] = overtime > 0 ? this.specialRound(overtime) : ''; // Number 或空字符串
            }
        },

        generateEmployeeRows(employeeData) {
            // 生成员工数据行，处理数组以确保正确的数据类型
            const baseRow = [employeeData.empId, employeeData.name, employeeData.department];
            const normalTimeRow = this.convertArray(employeeData.normalTimeArr);
            const overTimeRow = this.convertArray(employeeData.overTimeArr);
            return [
                [...baseRow, ...employeeData.attendanceData],            // 第一行：打卡数据
                [...baseRow, ...employeeData.vacationData],             // 第二行：休假数据
                [...baseRow, ...normalTimeRow, employeeData.contrastArr.join('\r\n')], // 第三行：工作时间 + 异常信息
                [...baseRow, ...overTimeRow]                            // 第四行：加班时间
            ];
        },

        convertArray(arr) {
            // 辅助函数：转换数组，将空字符串转换为 null
            return arr.map(value => value === '' ? null : value);
            // 空字符串转换为 null，以便 XLSX 识别为空单元格
            // Number 类型保持不变，String 类型（如“事”、“08:00”）保持为字符串
        },

        // 导出功能
        exportFile() {
            // 导出打卡统计结果
            this.exportExcel(this.processedData, '考勤统计结果.xlsx');
        },

        exportAllFile() {
            // 导出汇总数据
            this.exportExcel(this.summaryTableData, '考勤汇总数据.xlsx', true);
        },

        exportExcel(data, filename, isSummary = false) {
            // 导出 Excel 文件，设置列宽和行高
            const ws = XLSX.utils.aoa_to_sheet(data);
            const columnCount = data[0]?.length || 3;
            ws['!cols'] = Array(columnCount).fill({ wch: 20 });

            if (isSummary) {
                ws['!rows'] = data.map((row, index) => {
                    if (index === 0) return { hpx: 20 };
                    const adjustedIndex = index - 1;
                    const groupPosition = adjustedIndex % 4;
                    return groupPosition <= 1 ? { hpx: 60 } : { hpx: 20 };
                });
            }

            const wb = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(wb, ws, "考勤结果");
            XLSX.writeFile(wb, filename);
        },

        processSummaryData(jsonData) {
            // 处理汇总数据，生成最终结果
            const results = [];
            const dateStatusArr = new Array(this.dateLength).fill(0);

            // 正则表达式定义假期和加班关键词
            const overtimeKeywords = /^(加班)/;
            const keywords = /^(事假|年假|病假|产假|陪产假|婚假|例假|丧假|哺乳假)/;
            const allkeywords = /^(加班|事假|年假|病假|产假|陪产假|婚假|例假|丧假|哺乳假)/;

            // 修改后的正则表达式，支持匹配多个事件
            const eventKeyWords = /(加班|事假|年假|病假|产假|陪产假|婚假|例假|丧假|哺乳假)[\s\u4e00-\u9fa5]*(\d{2})-(\d{2})\s(\d{2}:\d{2})到(\d{2})-(\d{2})\s(\d{2}:\d{2})\s+(\d+\.?\d*)(小时|天)/g;

            // 阶段1：构建基础数据，收集员工的假期和加班事件
            for (let i = this.config.SummaryTableConfig.headCol; i < jsonData.length; i++) {
                const row = jsonData[i];
                const empId = row[this.config.SummaryTableConfig.empIdCol];
                const name = row[this.config.SummaryTableConfig.nameCol];

                if (!empId || !name) continue;

                if (!this.checkInTableObjectData[empId]) {
                    console.warn(`工号 ${empId} 不存在于打卡数据中，已跳过`);
                    continue;
                }

                let matterArr = [];
                let overtimeArr = [];
                let allmatterArr = [];
                for (let col = this.config.SummaryTableConfig.startCol; col < this.config.SummaryTableConfig.startCol + this.dateLength; col++) {
                    const dayIndex = col - this.config.SummaryTableConfig.startCol;
                    const cellContent = row[col] || '';

                    if (cellContent.includes("正常")) {
                        dateStatusArr[dayIndex]++;
                    } else if (cellContent.includes("休息")) {
                        dateStatusArr[dayIndex]--;
                    }

                    // 使用修改后的正则表达式匹配所有事件
                    let matches;
                    while ((matches = eventKeyWords.exec(cellContent)) !== null) {
                        const trimmedPart = matches[0].trim();
                        if (keywords.test(trimmedPart)) {
                            matterArr.push(trimmedPart);
                        }
                        if (overtimeKeywords.test(trimmedPart)) {
                            overtimeArr.push(trimmedPart);
                        }
                        if (allkeywords.test(trimmedPart)) {
                            allmatterArr.push(trimmedPart);
                        }
                    }
                }

                this.checkInTableObjectData[empId]["matterArr"] = [...new Set(matterArr)];
                this.checkInTableObjectData[empId]["overtimeArr"] = [...new Set(overtimeArr)];
                this.checkInTableObjectData[empId]["allmatterArr"] = [...new Set(allmatterArr)];
                
            }
            
            for (const [empId, empData] of Object.entries(this.checkInTableObjectData)) {
                for (let dayIdx = 0; dayIdx < this.dateLength; dayIdx++) {
                    const normalTime = empData.normalTimeArr[dayIdx] || '';
                    const overtime = empData.overTimeArr[dayIdx] || '';
                    if (dateStatusArr[dayIdx] < 0 && !String(normalTime).includes(":")) {
                        if ((normalTime === "" || normalTime === "0.0") && (overtime === "" || overtime === "0.0")) {
                            continue;
                        }
                        empData.overTimeArr[dayIdx] = Number(normalTime) + Number(overtime); // 转换为 Number
                        empData.normalTimeArr[dayIdx] = "";
                    } else {
                    }
                }
            }
            // 阶段3：处理考勤事件，包括假期类型和加班调整
            for (const [empId, empData] of Object.entries(this.checkInTableObjectData)) {
                empData.processedOvertimeArr = new Array(this.dateLength).fill('');
                empData.pMatterArr = new Array(this.dateLength).fill(''); // 初始化 pMatterArr
                if (empData.matterArr && empData.matterArr.length > 0) {
                    empData.matterArr.forEach(event => {
                        let matches;
                        const eventList = [];
                        const eventStr = event;
                        eventKeyWords.lastIndex = 0; // 重置正则表达式索引
                        while ((matches = eventKeyWords.exec(eventStr)) !== null) {
                            eventList.push(matches);
                        }
                        eventList.forEach(matched => {
                            const eventType = matched[1];
                            const startDay = parseInt(matched[3]);
                            const endDay = parseInt(matched[6]);
                            if (startDay === endDay) {
                                this.processSingleDayEvent(empData, matched, dateStatusArr);
                            } else {
                                this.processMultiDayEvent(empData, matched, dateStatusArr);
                            }
                        });
                    });
                }

                if (this.checkInTableObjectData[empId]["identity"] === "admin") {
                    this.checkInTableObjectData[empId]["processedOvertimeArr"] = this.checkInTableObjectData[empId]["overTimeArr"];
                    continue;
                }

                if (empData.overtimeArr && empData.overtimeArr.length > 0) {
                    empData.overtimeArr.forEach(event => {
                        let matches;
                        const eventList = [];
                        const eventStr = event;
                        eventKeyWords.lastIndex = 0; // 重置正则表达式索引
                        while ((matches = eventKeyWords.exec(eventStr)) !== null) {
                            eventList.push(matches);
                        }
                        eventList.forEach(matched => {
                            const eventType = matched[1];
                            if (eventType === "加班") {
                                const startDay = parseInt(matched[3]);
                                const endDay = parseInt(matched[6]);
                                if (startDay === endDay) {
                                    this.processSingleDayEvent(empData, matched, dateStatusArr);
                                    const dayIndex = startDay - 1;
                                    empData.processedOvertimeArr[dayIndex] = empData.overTimeArr[dayIndex];
                                } else {
                                    this.processMultiDayEvent(empData, matched, dateStatusArr);
                                    const startDate = startDay;
                                    const endDate = endDay;
                                    for (let day = startDate - 1; day < endDate; day++) {
                                        empData.processedOvertimeArr[day] = empData.overTimeArr[day];
                                    }
                                }
                            }
                        });
                    });
                }

                if (empData.allmatterArr && empData.allmatterArr.length > 0) {
                    empData.allmatterArr.forEach(event => {
                        let matches;
                        const eventList = [];
                        const eventStr = event;
                        eventKeyWords.lastIndex = 0; // 重置正则表达式索引
                        while ((matches = eventKeyWords.exec(eventStr)) !== null) {
                            eventList.push(matches);
                        }
                        eventList.forEach(matched => {
                            const eventType = matched[1];
                            const dayIndex = parseInt(matched[3]) - 1;

                            if (dayIndex < 0 || dayIndex >= this.dateLength) {
                                console.warn(`无效的日期索引: ${dayIndex} 对于事件: ${event}`);
                                return;
                            }
                            // 将所有事件完整记录到 pMatterArr
                            empData.pMatterArr[dayIndex] = empData.pMatterArr[dayIndex] ? 
                                empData.pMatterArr[dayIndex] + ',' + matched[0] : matched[0];
                        });
                    });
                }
            }

            // 阶段4：处理异常数据，将包含 ":" 的单次打卡数据转为 ""
            for (const [empId, empData] of Object.entries(this.checkInTableObjectData)) {
                for (let dayIdx = 0; dayIdx < this.dateLength; dayIdx++) {
                    const normalTime = empData.normalTimeArr[dayIdx] || '';
                    if (String(normalTime).includes(":")) {
                        empData.normalTimeArr[dayIdx] = "";
                    }
                }
            }

            // 阶段5：生成结果表
            const header = ['工号', '姓名', '部门'];
            for (let i = this.config.checkInTableConfig.startCol; i < this.config.checkInTableConfig.startCol + this.dateLength; i++) {
                header.push(this.jsonData[this.config.checkInTableConfig.headCol - 1][i]);
            }
            header.push('异常信息');
            results.push(header);

            for (const [empId, empData] of Object.entries(this.checkInTableObjectData)) {
                const baseRow = [empData.empId, empData.name, empData.department];
                const normalTimeRow = this.convertArray(empData.normalTimeArr);
                const overTimeRow = this.convertArray(empData.processedOvertimeArr);
                results.push(
                    [...baseRow, ...empData.attendanceData],            // 第一行：打卡数据
                    [...baseRow, ...empData.pMatterArr],               // 第二行：休假数据（显示所有事件）
                    [...baseRow, ...normalTimeRow, (empData.contrastArr || []).join('\r\n')], // 第三行：工作时间 + 异常信息
                    [...baseRow, ...overTimeRow]                       // 第四行：加班时间
                );
            }

            return results;
        },
        //单独事件
        processSingleDayEvent(empData, matched, dateStatusArr) {
            // 处理单天事件，确保数值数据为 Number 类型
            const [allData, eventType, startMonth, startDay, startTime, endMonth, endDay, endTime, amount, unit] = matched;
            const dayIndex = parseInt(startDay) - 1;

            if (startDay !== endDay || dayIndex < 0 || dayIndex >= this.dateLength) {
                console.warn("单天事件日期无效或不匹配:", matched[0]);
                return;
            }

            if (eventType === "加班") {
                const actual = Number(empData.overTimeArr[dayIndex] || 0);//实际的
                const required = Number(amount);//申报的
                if (actual > required) {
                    empData.overTimeArr[dayIndex] = required; // Number 类型
                } else if (actual < required) {
                    empData.overTimeArr[dayIndex] = actual > 0 ? actual : '';
                }
                empData.processedOvertimeArr[dayIndex] = empData.overTimeArr[dayIndex]; // 确保加班时长显示
            } else {
                empData.vacationData[dayIndex] = allData;
                const normalTime = empData.normalTimeArr[dayIndex];
                if (!String(normalTime).includes(":")) {
                    const hours = unit === '小时' ? parseFloat(amount) : parseFloat(amount) * 8;
                    
                    // 需求1：事假按小时显示，年假等按天显示，低于8小时显示实际值
                    if (eventType === "事假") {
                        if(hours>=8){
                            empData.normalTimeArr[dayIndex] =eventType[0]
                        }
                    } else {
                        if(hours>=8){
                            empData.normalTimeArr[dayIndex] =eventType[0]
                        }
                    }
                } else {
                    empData.normalTimeArr[dayIndex] = '';
                }
            }
        },
        //跨天事件
        processMultiDayEvent(empData, matched, dateStatusArr) {
            // 处理跨天事件，确保数值数据为 Number 类型
            const [allData, eventType, startMonth, startDay, startTime, endMonth, endDay, endTime, amount, unit] = matched;

            if (startMonth !== endMonth) {
                console.warn("暂不支持跨月处理:", matched[0]);
                return;
            }

            const startDate = parseInt(startDay);
            const endDate = parseInt(endDay);
            const days = endDate - startDate + 1;
            const dateRange = Array.from({ length: days }, (_, i) => startDate + i);

            if (eventType === "加班") {
                let totalOvertime = 0;
                dateRange.forEach(currentDay => {
                    const dayIndex = currentDay - 1;
                    if (dayIndex >= 0 && dayIndex < this.dateLength) {
                        totalOvertime += Number(empData.overTimeArr[dayIndex] || 0);
                    }
                });

                const required = Number(amount);
                if (totalOvertime > required) {
                    let remaining = totalOvertime - required;
                    for (let i = dateRange.length - 1; i >= 0 && remaining > 0; i--) {
                        const dayIndex = dateRange[i] - 1;
                        if (dayIndex >= 0 && dayIndex < this.dateLength) {
                            const currentOvertime = Number(empData.overTimeArr[dayIndex] || 0);
                            if (currentOvertime > remaining) {
                                empData.overTimeArr[dayIndex] = currentOvertime - remaining;
                                empData.processedOvertimeArr[dayIndex] = empData.overTimeArr[dayIndex]; // 确保加班时长显示
                                remaining = 0;
                            } else {
                                empData.overTimeArr[dayIndex] = '';
                                empData.processedOvertimeArr[dayIndex] = ''; // 确保加班时长显示
                                remaining -= currentOvertime;
                            }
                        }
                    }
                } else if (totalOvertime < required) {
                    empData.contrastArr[startDate - 1] = `[加班异常] 日期${startDate}-${endDate} 要求:${required}${unit} 实际:${totalOvertime}小时`;
                }
            } else {
                dateRange.forEach(currentDay => {
                    const dayIndex = currentDay - 1;
                    if (dayIndex >= 0 && dayIndex < this.dateLength) {
                        empData.vacationData[dayIndex] = allData;
                        if (!String(empData.normalTimeArr[dayIndex]).includes(":")) {
                            const hoursPerDay = unit === '小时' ? parseFloat(amount) : parseFloat(amount) * 8;
                            // 需求1：事假按小时显示，年假等按天显示，低于8小时显示实际值
                            if (eventType === "事假") {
                                if(hoursPerDay>=8){
                                    empData.normalTimeArr[dayIndex] =eventType[0]
                                }
                            } else {
                                if(hoursPerDay>=8){
                                    empData.normalTimeArr[dayIndex] =eventType[0]
                                }
                            }
                        }
                    }
                });
            }
        },
        
    }
});